
<?php
/**   
 * @Title:AbstractBean.php
 * @Description: 数据库操作的基础类（里面集成了基本的增删改查的方法）
 * @author tangchuan
 * @CreateDate 2016-03-01
 * @version V1.0
 */
/* 标示当前记录状态为未改变*/
define("DATA_ROW_STATE", "_data_row_state");
define("KEY_VALUE", "_key_value");
/* 标示当前记录状态为未改变*/
define("NO_CHANGE", 1);
/* 标示当前记录状态为未删除*/
define("DELETED", 4);
/* 标示当前记录状态为未新增*/
define("NEW", 2);
/* 标示当前记录状态为未修改*/
define("EDIT", 3);

require_once ('pdo_db.php');
require_once ('Child.php');
require_once ('SqlFilter.php');

class AbstractBean {
    protected $_table = "";
    protected $_prefix = "";
    protected $_className = "";
    protected $_primarykey = "";
    /*存储当前记录的字段名以及值*/
    protected $attributes = array();
    /**
     * 以键值对的形式保存当前对象关联的从表（通过addChild方法添加的）对象的数据集合
     * 其中键为从表对象的Class,值为与当前主表关联的从表记录的对象集合
     */
    public $childrenData = array();
    /* 字段列表*/
    protected $_fields = array();
    /* 字段名称*/
    protected $_field_labels = array();
    /*数据库连接*/
    protected $connection = null;
    /*当前对象那个销毁的时候是否禁止关闭数据库*/
    protected $forbidGC = false;
    /**
     * 从表的关系集合，以键值对的形式保存于当前模型关联的从表关系
     */
    protected $_childMap = array();
    /*数据库配置信息*/
    protected $defDbCfg = null;
    protected $_table_alias = "";
    protected $_autoIncrease = true;
    /**
     * 当前表中的非空的字段列表
     * 如果设置了改字段在调用保存到 时候会先对当前集合中字段的值逐一做非空验证
     * 如果验证通过就继续保存动作，如果不通过会向调用方抛出异常
     */
    protected $_mustFields = array();
    /**
     * 当前表中的不能重复的字段列表
     * 如果设置了改字段在调用保存到 时候会先对当前集合中字段的值逐一做唯一性验证
     * 如果验证通过就继续保存动作，如果不通过会向调用方抛出异常
     */
    protected $_uniqueFields = array();
    protected static $childs = array();
    /*标识当前记录在保存前是否以及通过验证*/
    protected $_validated = true;
    /*标识当前记录在保存前是否以及通过验证*/
    protected $_parentNode = null;
    public static $DATA_ROW_STATE = "_data_row_state";


    /**
     * 验证数据唯一性
     * @param $className 需要验证模型类名 （必填）
     * @param $field 需要验证的字段名称  （必填）
     * @param $value 需要验证的字段的值 （必填）
     * @param $keyValue 记录的主键值 （非必填）
     * @param $conn 数据库连接  （非必填）
     * @return 唯一返回true，否则返回false
     */

    public static function UniqueValidate($className, $field, $value, $keyValue = null, $conn = null) {
        $unique = true;
        try {
            //$bean = new AbstractBean();
            $bean = AbstractBean::LoadBean($className);
            if ($keyValue == null || $keyValue == "") {
                $keyValue = - 1;
            }
            $bean->connection = $conn;
            if ($bean->_table_alias != "" && count(explode(".", $field)) < 2) {
                $field = $bean->_table_alias . "." . $field;
            }
            /* $rows = $bean->fetchArray(array(
                         $field => $value
                     ));*/
            $rows = $bean->fetchArray(new SqlFilter($field, EQUALS, $value));
            $primaryKey = $bean->getParmaryKey();
            for ($i = 0;$i < count($rows);$i++) {
                $row = $rows[$i];
                $key = $row[$primaryKey];
                if ($key != null && $key != $keyValue) {
                    $unique = false;
                    break;
                }
            }
        }
        catch(Exception $ex) {
            echo $ex->getMessage();
        }
        return $unique;
    }


    /**
     * 调用某个实体的方法并通过当模型进行传参调用
     * @param $bean 模型实例 （必填）
     * @param $funcName 方法名称  （必填）
     * @param $instance 实体 （必填）
     * @return 返回$funcName方法的调用结果
     */
    public static function invokeFunc($bean, $funcName, $instance) {
        $rtn = null;
        $clazz = new ReflectionClass(get_class($instance));
        $func = $clazz->getMethod($funcName);
        $fParams = $func->getParameters();
        $rParams = array();
        if ($fParams != null) {
            for ($i = 0;$i < count($fParams);$i++) {
                array_push($rParams, $bean->get($fParams[$i]->name));
            }
            $rtn = $func->invokeArgs($instance, $rParams);
        }
        return $rtn;
    }

     /**
     * 把JSON字符串转换为特定的模型实例
     * @param $jsonData  需要转换的JSON字符串（必填）
     * @param $className 需要转换的模型名称  （必填）
     * @return 返回的一个包含jsonData数据的的模型实例
     */
    public static function ConvertJson2Bean($jsonData, $className = "") {
        $bean = null;
        if (is_string($jsonData)) {
            $jsonData = json_decode($jsonData);
        }
        if (is_object($jsonData) || is_array($jsonData)) {
            if ($className == null || $className == "") {
                $className = $jsonData->_model_name;
            }
            if ($className != null) {
                $bean = AbstractBean::LoadBean($className);
                $bean->json2Model($jsonData);
            }
        }
        return $bean;
    }


    /**
     * 根据模型名称查询对应的模型列表
     * @param $className  需要验证模型类名（必填）
     * @param $filter     过滤条件  （非必填）
     * @param $orderBy    排序字符串（非必填）
     * @param $limit      返回的最大记录数量 （非必填）
     * @param $groupBy    需要转换的模型名称 （非必填）
     * @return 返回符合查询条件的模型列表
     */
    public static function getBeanList($className=null, $filter = array(), $orderBy = "", $limit = 0, $groupBy = "") {
        if($className == null){
            $className = $this->_className;
        }
        $bean = AbstractBean::LoadBean($className);
        return $bean->fetchBeanList($filter, $orderBy, $limit, $groupBy);
    }


    /**
     * 根据类名称去加载一个模型的实体
     * @param $name       需要加载的模型类名（必填）
     * @param $key        实体的主键值  （非必填）
     * @param $loadChild  是否加载对应的从表记录   
     * @return 如果$key为空则返回一个$name类型新实例，如果$key非空则返回$key对应的记录
     */
    public static function LoadBean($name, $key = null, $loadChild = false) {
        $className = $name;
        $bean = null;
        if (!empty(self::$childs['table']) && array_key_exists($className, self::$childs['table']) && self::$childs['table'][$className] instanceof $className) {
            $class = get_class(self::$childs['table'][$className]);
            $bean = new $class();
            $bean->_className = $className;
        } else {
            try {
                //$class = Ymvc::loadTable($className);
                $file = APP_PATH . DIRECTORY_SEPARATOR . MODELS_PATH . DIRECTORY_SEPARATOR . $name . ".php";
                if (is_readable($file)) {
                    require_once $file;
                    $class = new $name();
                    @self::$childs['table'][$className] = $class;
                    $bean = @self::$childs['table'][$className];
                    $bean->_className = $className;
                }
            }
            catch(Exception $e) {
                die();
            }
        }
        if ($bean != null && $key != null && !empty($key)) {
            $bean->loadSelf($key);
            if ($loadChild == true) {
                $bean->loadChildren();
            }
        }
        return $bean;
    }


    /**
     * 执行一个带参数的sql
     * @param $sql       sql语句（必填）
     * @param $params     参数集合 （非必填）
     * @return 返回sql语句的执行结果
     */
    public static function executeSql($sql, $params = array()) {
        $conn = AbstractDbUtils::GetOpenedConnection();
        if ($conn != null) {
            $conn->executeSql($sql, $params);
        }
    }

    /**
     * 获取当前模型对应的数据库表名称及_tableName值
     * @return 返回当前模型对应的数据库表名称及_tableName值
     */

    public function getTableName() {
        return $this->_table;
    }


    /**
     * 设置当前模型对应的数据库表名称及_tableName值
      * @param $table     数据库表名称 （必填）
     */

    public function setTableName($table) {
        $this->_table = $table;
    }

     /**
     * 获取当前模型对应表的主键字段名
     * @return 前模型对应表的主键字段名
     */
    public function getPrimaryKey() {
        return $this->_primarykey;;
    }

    public function setPrimaryKey($keyName) {
        $this->_primarykey = $keyName;
    }


     /**
     * 获取一个可用的数据库连接对象
     * @param $key  数据库连接名称（非必填）
     * @param $transaction   创建该连接的时候是否开启事物 （非必填）
     * @return 返回一个可用的数据库连接对象
     */
    public function getOpenedConnection($key = CONNECTION_KEY, $transaction = false) {
        $conn = null;
        if (!empty($_REQUEST[$key])) {
            $conn = $_REQUEST[$key];
        }
        if (!($conn instanceof pdo_db) && $this->defDbCfg != null) {
            // print_r($this->defDbCfg);
            $_REQUEST[$key] = new pdo_db($this->defDbCfg["host"], $this->defDbCfg["user"], $this->defDbCfg["password"], $this->defDbCfg["database"]);
            $conn = $_REQUEST[$key];
            //print_r($conn);
            
        }
        return $conn;
    }

     /**
     * 保存方法调用之前做非空字段的校验
     * @return 通过返回true否则false
     */
    public function emptyCheck() {
        $this->_validated = false;
        if ($this->_mustFields != null) {
            $keys = array_keys($this->_mustFields);
            for ($i = 0;$i < count($keys);$i++) {
                $field = $keys[$i];
                $value = $this->get($field);
                if (!($value != null && $value != "")) {
                    return $field;
                }
            }
        }
        $this->_validated = true;
        return "";
    }


    /**
     * 保存方法调用之前做唯一性字段的校验
     * @return 通过返回true否则false
     */
    public function uniqueCheck() {
        $this->_validated = false;
        if ($this->_uniqueFields != null) {
            $keys = array_keys($this->_uniqueFields);
            for ($i = 0;$i < count($keys);$i++) {
                $field = $keys[$i];
                if (!AbstractBean::UniqueValidate($this->_className, $field, $this->get($field), $this->getKeyValue())) {
                    return $field;
                }
            }
        }
        $this->_validated = true;
        return "";
    }

    /**
     * 判断当前模型对象是否被持久化过
     * @return 通过返回true否则false
     */
    public function isNew() {
        /*$key = $this->_primarykey;
              if ($this->getStringValue($key) == "") {
                  return true;
              }*/
        $keyValue = $this->getKeyValue();
        if ($keyValue == null || $keyValue == "") {
            return true;
        }
        return false;
    }

     
    public function closeConnection() {
        try {
            if ($this->connection != null) {
                $this->connection->sql_close();
            }
        }
        catch(Exception $ex) {
            echo $ex->getMessage();
        }
    }

    /**
     * 获取当前模型对应表的主键字段名
     * @return 前模型对应表的主键字段名
     */
    public function getParmaryKey() {
        $field = $this->_primarykey;
        $arr = explode(".", $field);
        if (count($arr) > 1) {
            $field = $arr[1];
        }
        return $field;
    }


    /**
     * 返回一个字段去掉别名后的值
     * @return 返回一个字段去掉别名后的值
     */
    public function getField($field) {
        $arr = explode(".", $field);
        if (count($arr) > 1) {
            $field = $arr[1];
        }
        return $field;
    }


     /**
     * 获得符合查询条件的数据库记录数
     * @param $key  数据库连接名称（非必填）
     * @param $transaction   创建该连接的时候是否开启事物 （非必填）
     * @return 返回一个可用的数据库连接对象
     */
    public function getRecordCount($filter = array()) {
        $count = 0;
        try {
            $strFilter = "";
            $sql = $this->generateCountSqlWithFilter($filter);
            if ($this->connection == null || $this->connection == 0) {
                $this->connection = $this->getOpenedConnection();
            }
            if ($this->connection instanceof pdo_db) {
                $map = array();
                if ($filter != null && $filter instanceof SqlFilter) {
                    $map = $filter->value_map;
                }
                $count = $this->connection->fetchColumn($sql, $map);
            } else if ($this->connection instanceof sql_db) {
                $this->connection->sql_query($sql);
                $count = $this->connection->sql_fetchfield("total");
            }
        }
        catch(Exception $ex) {
            echo $ex->getMessage() . "</br>" . $ex->getTraceAsString();
        }
        return $count;
    }


     /**
     * 设置模型的一个字段的值
     * @param $name  需要设置的字段名称
     * @param $value   需要设置的字段的值
     */
    public function set($name, $value) {
        $name = $this->getField($name);
        $this->$name = $value;
        $this->attributes[$name] = $value;
    }


     /**
     * 获取模型的一个字段的值     
     * @param $name   需要设置的字段的值
     * @return 获取模型的一个字段的值
     */
    public function get($name) {
        $value = null;
        $field = $this->getField($name);
        if (array_key_exists($field, $this->attributes)) {
            $value = $this->attributes[$field];
        } else if (array_key_exists($name, $this)) {
            $value = $this->$name;
        }
        return $value;
    }

    /**
     * 获取当前模型实例对应的数据库主键值     
     * @return 当前模型实例对应的数据库主键值     
     */
    public function getKeyValue() {
        return $this->get($this->getParmaryKey());
    }

    public function getStringValue($name) {
        $value = "";
        $field = $this->getField($name);
        if (array_key_exists($field, $this->attributes)) {
            $value = $this->attributes[$field] . "";
        }
        return $value;
    }

    /**
     * 添加与当前对象管理的从表关系，设置了关系后
     * 当前对象被删除方法后，从表记录会被自动删除
     * 当掉用了查询方法（仅当设置了loadChild=true后）对应的从表记录会被自动删除或自动加载    
     * 当调用了save放发后，当前模型从表集合中的记录会被自动保存
     * @param $childClass   需要设置的字段的值
     * @param $parentField   需要设置的字段的值
     * @param $childField   需要设置的字段的值
     * @param $is_view   需要设置的字段的值
     */
    public function addChild($childClass, $parentField = "", $childField = "", $is_view = false) {
        if ($parentField == "") {
            $parentField = $this->_primarykey;
        }
        if ($childField == "") {
            $childField = $this->_primarykey;
        }
        $this->_childMap[$childClass] = new Child($childClass, $parentField, $childField, $is_view);
    }

     /**
     * 根据现有主从关系想一个对应的从表集合中添加懂表记录（调用保存方法的时候从表记录也会被保存）
     * @param $childClass   需要设置的字段的值
     * @param $parentField   需要设置的字段的值
     * @param $childField   需要设置的字段的值
     * @param $is_view   需要设置的字段的值
     */
    public function addChildRecord($childBean) {
        if ($childBean != null) {
            $childName = get_class($childBean);
            if (array_key_exists($childName, $this->_childMap)) {
                $list = array();
                if (array_key_exists($childName, $this->childrenData)) {
                    $list = $this->childrenData[$childName];
                }
                array_push($list, $childBean);
                $this->childrenData[$childName] = $list;
            }
        }
    }


    /**
     * 根据查询条件查询符合filter条件的记录（以二维array形式返回查询结果）
     * @param $filter  过滤条件（非必填）
     * @param $orderBy 排序规则
     * @param $limit   返回的最大记录数
     * @param $groupBy group by 规则
     */
    public function fetchArray($filter = array(), $orderBy = "", $limit = 0, $groupBy = "") {
        if ($this->connection == null || $this->connection == 0) {
            $this->connection = $this->getOpenedConnection();
        }
        //print_r($this->connection);
        if ($this->connection instanceof pdo_db) {
            return $this->queryByPdo($filter, $orderBy, $limit, $groupBy);
        } else if ($this->connection instanceof sql_db) {
            return $this->query($filter, $orderBy, $limit, $groupBy);
        }
    }

    /**
     * 根据查询条件查询符合filter条件的记录（以模型数组形式形式返回查询结果）
     * @param $filter  过滤条件（非必填）
     * @param $orderBy 排序规则
     * @param $limit   返回的最大记录数
     * @param $loadChild 是否自动加载从表记录
     */
    public function fetchBeanList($filter = array(), $orderBy = "", $limit = 0, $loadChild = false) {
        $beanList = array();
        $rows = array();
        if ($this->connection == null) {
            $this->connection = $this->getOpenedConnection();
        }
        //print_r($this->connection);
        if ($this->connection instanceof pdo_db) {
            $rows = $this->queryByPdo($filter, $orderBy, $limit);
        } else if ($this->connection instanceof sql_db) {
            $rows = $this->query($filter, $orderBy, $limit);
        }
        $fields = null;
        for ($i = 0;$i < count($rows);$i++) {
            $row = $rows[$i];
            $bean = AbstractBean::LoadBean($this->_className);
            $bean->connection = $this->connection;
            if ($fields == null) {
                $fields = array_keys($row);
            }
            for ($j = 0;$j < count($fields);$j++) {
                $col = $fields[$j];
                $bean->set($col, $row[$col]);
            }
            if ($loadChild == true) {
                $bean->loadChildren();
            }
            $beanList[$i] = $bean;
        }
        return $beanList;
    }

     /**
     * 根据主键刷险当前模型对象里面的数据
     */
    public function reload() {
        return $this->loadSelf($this->get($this->_primarykey));
    }


     /**
     * 根据字段值加载一条数据库记录到当前模型对象
     * @param $key  关键字值
     * @param $field 关键字默认为主键字段（非必填）  
    */
    public function loadSelf($key, $field = "") {
        $success = false;
        try {
            //$filter = new SqlFilter();
            if ($field == null || $field == "") {
                $field = $this->_primarykey;
                if ($this->_table_alias != "") {
                    $field = $this->_table_alias . "." . $field;
                }
            }
            $filter = new SqlFilter($field, EQUALS, $key);
            $rows = $this->fetchArray($filter);
            if (count($rows) > 0) {
                $row = $rows[0];
                $arr = ((array)$row);
                $cols = array_keys($arr);
                for ($i = 0;$i < count($cols);$i++) {
                    $key = $cols[$i];
                    $this->set($key, $arr[$key]);
                }
                $this->set(KEY_VALUE, $this->getKeyValue());
                //$this->_fields = $cols ;
                $success = true;
            }
        }
        catch(Exception $ex) {
            echo $ex->getMessage() . "</br>" . $ex->getTraceAsString();
        }
        return $success;
    }

    /**
     * 根据filter加载第一条符合条件的记录
     * @param $filter  过滤条件
     * @param $orderBy 排序规则
    */
    public function loadFirst($filter, $orderBy = "") {
        $success = false;
        try {
            //$filter = new SqlFilter();
            $rows = $this->fetchArray($filter, $orderBy);
            if (count($rows) > 0) {
                $row = $rows[0];
                $arr = ((array)$row);
                $cols = array_keys($arr);
                for ($i = 0;$i < count($cols);$i++) {
                    $key = $cols[$i];
                    $this->set($key, $arr[$key]);
                }
                //$this->_fields = $cols ;
                $success = true;
            }
        }
        catch(Exception $ex) {
            echo $ex->getMessage() . "</br>" . $ex->getTraceAsString();
        }
        return $success;
    }

    /**
     * 生成默认的查询语句（当查询复杂的时候应该在派生类中重载改方法）
    */
    protected function generateSql() {
        $sql = "select * from " . $this->_table;
        return $sql;
    }


    protected function generateCountSql() {
        $table = $this->_table;
        $primaryKey = $this->getParmaryKey();
        if ($this->_table_alias != "") {
            $table = $table . " " . $this->_table_alias;
            $primaryKey = $this->_table_alias . "." . $primaryKey;
        }
        $sql = $this->generateSql();
        $sql = preg_replace("/select\s+(.*?)\s+from/is", "select count(" . $primaryKey . ") as total from ", $sql);
        return $sql;
    }

    /**
     * 1、保存当前模型对象的数据到数据库(根据主键字段是否为空自动决策调用insert还是update)
     * 2、如果当前模型设置了主从关系，切模型的从表列表中有记录则，从表记录也会被递归保存即会触发从表对象的save方法
     * 3、如果从表记录中状态为DELETED则从表记录会被删除
     * @return 成功返回true,否则返回false
     */
    public function save() {
        $success = false;
        try {
            if ($this->connection == null) {
                $this->connection = $this->getOpenedConnection();
            }
            if ($this->isNew()) {
                $this->insertItem();
            } else {
                $this->update();
            }
            $childClss = array_keys($this->_childMap);
            for ($i = 0;$i < count($childClss);$i++) {
                //$childList = $this->loadChild($childClss[$i],false);
                $rel = $this->_childMap[$childClss[$i]];
                $childList = $this->getChildBeanList($childClss[$i], false);
                if ($childList == null || count($childList) == 0) {
                    continue;
                }
                for ($j = 0;$j < count($childList);$j++) {
                    $childBean = $childList[$j];
                    $childBean->_parentNode = $this;
                    $childBean->set($rel->_childColumn, $this->get($rel->_parentColumn));
                    $state = $childBean->get(DATA_ROW_STATE);
                    if ($state == NO_CHANGE) {
                        continue;
                    } else if ($state == DELETED) {
                        $childBean->deleteItem();
                    } else {
                        $childBean->save();
                    }
                }
            }
            $success = true;
        }
        catch(Exception $ex) {
            echo $ex->getMessage() . "<br>" . $ex->getTrace() . "<br>";
        }
        return $success;
    }


    protected function query($filer = array(), $orderBy = "", $limit = 0, $groupBy = "") {
        $rows = array();
        try {
            $strFilter = "";
            $sql = "select * from " . $this->_table . " " . $this->_table_alias;
            if ($limit > 0) {
                $sql = "select top " + $limit + " * from " . $this->_table . " " . $this->_table_alias;
            }
            if ($filer != null) {
                if (is_array($filer)) {
                    $cols = array_keys($filer);
                    for ($i = 0;$i < count($cols);$i++) {
                        $key = $cols[$i];
                        $value = $filer[$key];
                        if ($value != null && $value != "") {
                            $spit = $strFilter == "" ? "" : " and ";
                            $strFilter.= $spit . $key . "= '" . $value . "'";
                        }
                    }
                } else {
                    $strFilter = $filer;
                }
                if ($strFilter != "") {
                    $sql.= " where " . $strFilter;
                }
            }
            if ($groupBy != "") {
                $sql.= $groupBy;
            }
            if ($orderBy != "") {
                $sql.= " " . $orderBy;
            }
            /* if ($limit > 0) {
                         $sql.= " limit " . $limit;
                     }*/
            $this->connection->sql_query($sql);
            $rows = $this->connection->sql_fetchrowset();
        }
        catch(Exception $ex) {
            echo $ex->getMessage() . "</br>" . $ex->getTraceAsString();
        }
        return $rows;
    }

    


    protected function generateCountSqlWithFilter($filter = array()) {
        //$sql = "select count(*) as total from " . $this->_table;
        $sql = $this->generateCountSql();
        if ($filter != null) {
            if ($filter instanceof SqlFilter) {
                $strFilter = $filter->toSqlExpress();
            } else if (is_array($filter)) {
                $cols = array_keys($filter);
                for ($i = 0;$i < count($cols);$i++) {
                    $key = $cols[$i];
                    $value = $filter[$key];
                    if ($value != null && $value != "") {
                        $spit = $strFilter == "" ? "" : " and ";
                        $strFilter.= $spit . $key . "= '" . $value . "'";
                    }
                }
            } else {
                $strFilter = $filter;
            }
            if ($strFilter != "") {
                //$sql.= " where " . $strFilter;
                $spit = strstr($sql, "where") == false ? " where " : " and ";
                if (stristr($sql, "{filter}") == false) {
                    $sql.= $spit . $strFilter;
                } else {
                    $sql = str_replace("{filter}", $spit . $strFilter, $sql);
                }
            }
        }
        return $sql;
    }


    protected function generateQuerySql($filter = array(), $limit = - 1) {
        $strFilter = "";
        $sql = $this->generateSql();
        if ($filter != null) {
            if ($filter instanceof SqlFilter) {
                $strFilter = $filter->toSqlExpress();
            } else if (is_array($filter)) {
                $cols = array_keys($filter);
                for ($i = 0;$i < count($cols);$i++) {
                    $key = $cols[$i];
                    $value = $filter[$key];
                    //$value = iconv('utf-8','gb2312',$value);
                    if ($value != null && $value != "") {
                        $spit = $strFilter == "" ? "" : " and ";
                        $strFilter.= $spit . $key . "= '" . $value . "'";
                    }
                }
            } else {
                $strFilter = $filter;
            }
        }
        if ($strFilter != "") {
            $spit = strstr($sql, "where") == false ? " where " : " and ";
            if (stristr($sql, "{filter}") == false) {
                $sql.= $spit . $strFilter;
            } else {
                $sql = str_replace("{filter}", $spit . $strFilter, $sql);
            }
        }
        return $sql;
    }


    protected function queryByPdo($filter = array(), $orderBy = "", $limit = 0, $groupBy = "") {
        $rows = array();
        try {
            if ($this->connection == null) {
                $this->connection = $this->getOpenedConnection();
            }
            $conn = $this->connection;
            // $this->getcols();
            $sql = $this->generateQuerySql($filter);
            $reverseOrderBy = $orderBy;
            if (strstr($reverseOrderBy, "desc")) {
                $reverseOrderBy = str_replace("desc", "asc", $reverseOrderBy);
            } else if (strstr($reverseOrderBy, "asc")) {
                $reverseOrderBy = str_replace("asc", "desc", $reverseOrderBy);
            }
            $start = 0;
            if (is_string($limit)) {
                $arr = explode(",", $limit);
                if (count($arr) > 1) {
                    $start = $arr[0];
                    $limit = $arr[1];
                }
            }
            if ($limit > 0) {
                //$sql="select top  ".($limit+$start)." ". $this->_primarykey." from (". $sql .") a " . $reverseOrderBy;
                $prefix = $this->_table_alias;
                if ($prefix != "") {
                    $prefix = $prefix . ".";
                }
                if (count($filter) == 0) {
                    $sql = str_replace("{filter}", "", $sql);
                }
                $sql_inner_tmp = preg_replace("/select\s+(.*?)\s+from/is", "select top " . ($start + $limit) . " " . $prefix . $this->_primarykey . " from ", $sql);
                $sql_inner_tmp.= " " . $reverseOrderBy;
                $sql_inner_tmp = "select top " . $limit . " " . $prefix . $this->_primarykey . " from (" . $sql_inner_tmp . ") a " . $orderBy;
                $sql_tmp = $this->generateQuerySql();
                $spit = strstr($sql_tmp, "where") == false ? " where " : " and ";
                if (stristr($sql_tmp, "{filter}") == false) {
                    $sql_tmp.= $spit . $prefix . $this->_primarykey . " in (" . $sql_inner_tmp . ")";
                } else {
                    $sql_tmp = str_replace("{filter}", $spit . $prefix . $this->_primarykey . " in (" . $sql_inner_tmp . ")", $sql_tmp);
                }
                $sql = $sql_tmp;
            }
            if ($groupBy != "") {
                $sql.= " " . $groupBy;
            }
            if ($orderBy != "") {
                $sql.= " " . $orderBy;
            }
            // echo "<br>==================================<br>".$sql."<br>==================================<br>";
            $conn->prepare($sql);
            if ($filter instanceof SqlFilter) {
                $conn->execute($filter->params);
            } else {
                $conn->execute(array());
            }
            $rs = $conn->fetchAll();
            for ($i = 0;$i < count($rs);$i++) {
                $row = (array)$rs[$i];
                $keys = array_keys($row);
                for ($j = 0;$j < count($keys);$j++) {
                    $key = $keys[$j];
                    $value = $row[$key];
                    $value = $this->__iconv($value);
                    $row[$key] = $value;
                }
                $rows[] = (array)$row;
            }
        }
        catch(Exception $ex) {
            echo $ex->getMessage() . "</br>" . $ex->getTraceAsString();
        }
        return $rows;
    }

    

    public function _initcols() {
        try {
            $sql = "select  * from " . $this->_table . " where 1=0";
            //echo $sql."<br>";
            if ($this->connection == null) {
                $this->connection = $this->getOpenedConnection();
            }
            if ($this->connection instanceof pdo_db) {
                $this->connection->query($sql);
                $count = $this->connection->columnCount();
                $metas = $this->connection->getColumnMetas($this->_table);
                for ($i = 0;$i < $count;$i++) {
                    try {
                        $meta = (array)$metas[$i];
                        $this->_fields[$meta["COLUMN_NAME"]] = $meta["TYPE_NAME"];
                    }
                    catch(Exception $ex1) {
                        echo $ex1->getMessage() . "</br>" . $ex1->getTraceAsString();
                    }
                }
            } else if ($this->connection instanceof sql_db) {
                $this->connection->sql_query($sql);
                $count = $this->connection->sql_numfields();
                for ($i = 0;$i < $count;$i++) {
                    $field = $this->connection->sql_fieldname($i);
                    $type = $this->connection->sql_fieldtype($i);
                    $this->_fields[$field] = $type;
                }
            }
        }
        catch(Exception $ex) {
            echo $ex->getMessage() . "</br>" . $ex->getTraceAsString();
        }
    }
    public function getcols() {
        if ($this->_fields == null || count($this->_fields) == 0) {
            $this->_initcols();
        }
        return $this->_fields;
    }
    public function loadChildren($forceReload = false,$filter=null) {
        $childClss = array_keys($this->_childMap);
        for ($i = 0;$i < count($childClss);$i++) {
            $list = $this->loadChild($childClss[$i], "", $forceReload,$filter);
            for ($j = 0;$j < count($list);$j++) {
                $list[$j]->loadChildren($forceReload,$filter);
            }
        }
    }
    public function getChildBeanList($childName, $forceReload = false,$filter = null) {
        if ($forceReload == true) {
            $this->loadChild($childName, "", true,$filter);
        }
        return $this->childrenData[$childName];
    }
    public function loadChild($childName, $orderBy, $forceReload = false,$filter=null) {
        $list = array();
        try {
            if (array_key_exists($childName, $this->_childMap)) {
                $childinfo = new Child();
                $childinfo = $this->_childMap[$childName];
                if (array_key_exists($childName, $this->childrenData) && $forceReload == false) {
                    $list = $this->childrenData->$childName;
                } else {
                    if ($childinfo->_parentColumn != null) {
                        
                        if($filter == null){
                            $filter = new SqlFilter();    
                        }
                        $parent_id = $this->get($childinfo->_parentColumn);
                        if ($parent_id == null) {
                            $parent_id = - 1;
                        }
                        //echo "parent_id:".$parent_id."<br/>";
                        $filter->addFilter($childinfo->_childColumn, EQUALS, $parent_id);
                        $childBean = AbstractBean::LoadBean($childinfo->_childClassName);
                        $childBean->connection = $this->connection;
                        $childBean->forbidGC = true;
                        $childList = $childBean->fetchBeanList($filter, $orderBy);
                        for ($i = 0;$i < count($childList);$i++) {
                            $child = $childList[$i];
                            $child->set(KEY_VALUE, $child->getKeyValue());
                            $child->set(DATA_ROW_STATE, NO_CHANGE);
                            $child->connection = $this->connection;
                            $list[$i] = $child;
                        }
                    }
                    $this->childrenData[$childName] = $list;
                }
            }
        }
        catch(Exception $ex) {
            echo $ex->getMessage() . "</br>" . $ex->getTraceAsString();
        }
        return $list;
    }
    
    public function insertItem() {
        if ($this->connection == null) {
            $this->connection = $this->getOpenedConnection();
        }
        if ($this->connection instanceof pdo_db) {
            $this->insertBypdo();
        } else if ($this->connection instanceof sql_db) {
            $this->insert();
        }
    }
    protected function insert() {
        try {
            $strFields = "";
            $strValue = "";
            $cols = array_keys($this->getcols());
            for ($i = 0;$i < count($cols);$i++) {
                $col = $cols[$i];
                if ($col != $this->_primarykey) {
                    $value = $this->attributes[$col];
                    $spit = $strFields == "" ? "" : ",";
                    if ($value != "") {
                        $strValue.= $spit . "'" . $value . "'";
                    } else {
                        $strValue.= $spit . "null";
                    }
                    if (strstr($col, "`") == false) {
                        $col = "`" . $col . "`";
                    }
                    $strFields.= $spit . $col;
                }
            }
            $sql = "INSERT INTO " . $this->_table . "(" . $strFields . ")values(" . $strValue . ");";
            $this->connection->sql_query($sql);
            $this->connection->sql_query("SELECT  @@IDENTITY AS id");
            $id = $this->connection->sql_fetchfield("id");
            $this->set($this->_primarykey, $id);
        }
        catch(Exception $ex) {
            echo $ex->getMessage() . "<br>" . $ex->getTrace() . "<br>";
        }
    }
    protected function insertBypdo() {
        try {
            $strFields = "";
            $strValue = "";
            $strValueDebug = "";
            $sql = "";
            $cols = array_keys($this->getcols());
            $params = array();
            for ($i = 0;$i < count($cols);$i++) {
                $col = $cols[$i];
                //如果字段是铸件且主键为自增则跳过
                if ($col == $this->getParmaryKey() && $this->_autoIncrease || !array_key_exists($col, $this->attributes)) {
                    continue;
                }
                if ($col != $this->getParmaryKey()) {
                    $value = $this->attributes[$col];
                    $type = $this->_fields[$col];
                    if ($value == "") {
                        $value = null;
                    }
                    $spit = $strFields == "" ? "" : ",";
                    $strFields.= $spit . $col;
                    $strValue.= $spit . ":" . $col;
                    //$params[$col] = $this->_iconv($value,$type);
                    $params[$col] = $value;
                    $strValueDebug.= $spit . "'" . $value . "'";
                }
            }
            $sql.= "INSERT INTO " . $this->_table . "(" . $strFields . ")values(" . $strValue . ")";
            $sql2 = "INSERT INTO " . $this->_table . "(" . $strFields . ")values(" . $strValueDebug . ")";
            //echo $sql2."<br/>";
            if ($this->connection == null || $this->connection == 0) {
                $this->connection = $this->getOpenedConnection();
            }
            $conn = $this->connection;
            $conn->prepare($sql);
            //$conn->bindArray($params);
            $conn->execute($params);
            $id = $conn->fetchColumn("SELECT  @@IDENTITY AS id");
            $this->set($this->_primarykey, $id);
        }
        catch(Exception $ex) {
            echo $ex->getMessage() . "<br>" . $ex->getTrace() . "<br>";
        }
    }
    public function update() {
        if ($this->connection == null) {
            $this->connection = $this->getOpenedConnection();
        }
        if ($this->connection instanceof pdo_db) {
            $this->updateByPdo();
        } else if ($this->connection instanceof sql_db) {
            $this->updateBydb();
        }
    }
    protected function _iconv($value, $type) {
        return $value;
    }
    protected function __iconv($value, $type = "") {
        return $value;
    }
    public function updateByPdo() {
        $sql = "";
        try {
            $this->getcols();
            $dbcols = $this->_fields;
            $cols = array_keys($this->attributes);
            $params = array();
            $primaryKey = $this->getParmaryKey();
            if (count($cols) > 0) {
                $strFields = "";
                for ($i = 0;$i < count($cols);$i++) {
                    $col = $cols[$i];
                    if (array_key_exists($col, $dbcols) && $cols[$i] != $primaryKey) {
                        $spit = $strFields == "" ? "" : ",";
                        $value = $this->attributes[$col];
                        if ($value != "") {
                            //$params[$col] = $this->_iconv($value);
                            $params[$col] = $value;
                        } else {
                            $params[$col] = null;
                        }
                        $strFields.= $spit . $col . "=" . $col = ":" . $col;
                    }
                }
                $params[$primaryKey] = $this->attributes[$primaryKey];
                $sql.= " Update " . $this->_table . " set " . $strFields . " where " . $primaryKey . " =:" . $primaryKey;
                if ($this->connection == null) {
                    $this->connection = $this->getOpenedConnection();
                }
                $conn = $this->connection;
                $conn->prepare($sql);
                //$conn->bindArray($params);
                $conn->execute($params);
            }
        }
        catch(Exception $ex) {
            echo $ex->getMessage() . "</br>" . $ex->getTraceAsString();
        }
    }
    public function updateBydb() {
        try {
            $dbcols = $this->getcols();
            $cols = array_keys($this->attributes);
            if (count($cols) > 0) {
                $strValue = "";
                for ($i = 0;$i < count($cols);$i++) {
                    $col = $cols[$i];
                    if (array_key_exists($col, $dbcols) && $cols[$i] != $this->_primarykey) {
                        $spit = $strValue == "" ? "" : ",";
                        $value = $this->attributes[$cols[$i]];
                        if ($value != "") {
                            $strValue.= $spit . $cols[$i] . " ='" . $value . "'";
                        } else {
                            $strValue.= $spit . $cols[$i] . " =null";
                        }
                    }
                }
                $primaryKey = $this->getParmaryKey();
                $sql = " Update " . $this->_table . " set " . $strValue . " where " . $primaryKey . " ='" . $this->attributes[$primaryKey] . "'";
                $this->connection->sql_query($sql);
            }
        }
        catch(Exception $ex) {
            echo $ex->getMessage() . "</br>" . $ex->getTraceAsString();
        }
    }
    public function deleteItem() {
        $this->deleteChild();
        $this->delete();
    }
    public function deleteChild() {
        $keys = array_keys($this->_childMap);
        for ($i = 0;$i < count($keys);$i++) {
            $childName = $keys[$i];
            $childInfo = $this->_childMap[$childName];
            if ($childInfo->_is_view == false) {
                $childList = $this->loadChild($childName);
                //echo "child count:".count($childList);
                for ($j = 0;$j < count($childList);$j++) {
                    $child = $childList[$j];
                    $child->connection = $this->connection;
                    $child->deleteItem();
                }
            }
        }
    }
    function __destruct() {
        if ($this->forbidGC == false) {
            //$this->closeConnection();
            //echo $this->_table."=".$this->forbidGC ."<br>";
            
        }
    }
    protected function delete() {
        try {
            $primaryKey = $this->getParmaryKey();
            if ($this->connection == null || $this->connection == 0) {
                $this->connection = $this->getOpenedConnection();
            }
            if ($this->connection instanceof pdo_db) {
                $conn = $this->connection;
                $sql = "delete from " . $this->_table . " where " . $primaryKey . " =:" . $primaryKey;
                $conn->prepare($sql);
                $conn->prepare($sql);
                //$conn->bindArray($params);
                $conn->execute(array($this->_primarykey => $this->getKeyValue()));
                $conn->execute();
            } else if ($this->connection instanceof sql_db) {
                $sql = "delete from " . $this->_table . " where " . $primaryKey . " ='" . $this->getKeyValue() . "'";
                $this->connection->sql_query($sql);
            }
        }
        catch(Exception $ex) {
            echo $ex->getMessage() . "</br>" . $ex->getTraceAsString();
        }
    }
    protected function json2Model($jsonData) {
        /******填充主表数据*******/
        $jsonData = (array)$jsonData;
        $cols = $this->getcols();
        $keys = array_keys($jsonData);
        for ($i = 0;$i < count($keys);$i++) {
            $key = $keys[$i];
            $value = stripslashes($jsonData[$key]);
            $this->set($key, $value);
        }
        /******填充子表数据*******/
        if (array_key_exists("childrenData", $jsonData) && $jsonData["childrenData"] != null) {
            $childrenData = (array)$jsonData["childrenData"];
            $keys = array_keys($childrenData);
            for ($i = 0;$i < count($keys);$i++) {
                $key = $keys[$i];
                $childBeanList = array();
                $childList = (array)$childrenData[$key];
                for ($j = 0;$j < count($childList);$j++) {
                    $childData = $childList[$j];
                    $childBean = AbstractBean::LoadBean($childData["_className"]);
                    $childBean->json2Model($childData);
                    array_push($childBeanList, $childBean);
                }
                $this->childrenData[$key] = $childBeanList;
            }
        }
    }
}
?>
